<?php


namespace common\service;


use common\exception\LogicException;
use common\model\EntityModel;
use common\model\PlanModel;
use common\model\StepCategoryModel;
use common\model\StepModel;
use common\model\TaskModel;
use common\model\TaskRelationTagModel;
use support\EntityTaskFilterParser;
use support\ErrorCode;
use support\SingletonTrait;
use think\Exception;
use think\Hook;
use think\module\Module;

class ShotService
{
    /**
     * @var EntityModel
     */
    private $entityModel;

    use SingletonTrait;

    // 引用多模块实体任务筛选解析类
    use EntityTaskFilterParser;

    public function __construct()
    {
        $this->entityModel = model(EntityModel::class);
    }

    /**
     * 镜头合并模块实体任务树
     * @param $params
     * @param int $currentTenantId
     * @return array
     * @throws \Exception
     */
    public function getShotMergeModuleEntityTaskTree($params, int $currentTenantId)
    {
        $extraEntityFilter = $this->parseMultipleEntityTaskFilter($params['filter']);
        /**
         * 查询序列任务
         * 查询镜头任务
         * 组装树 序列=>镜头
         */
        $episodeId = $params['filter']['episode_id'] ?? 0;
        $projectId = $params['filter']['project_id'];
        $page = $params['page'] ?? [1, C("database.database_max_select_rows")];
        $order = $params['order'] ?? 'entity.showings_number,entity.name,entity.id';
        $sequenceModuleId = module_by_code('sequence')['id'];
        $shotModuleId = module_by_code('shot')['id'];
        $res = [
            'total' => 0,
            'rows' => []
        ];
        $optionService = OptionsService::getInstance();
        $mergeModuleConfig = $optionService->getOptionsData('merge_module_config');
        $moduleCodes = [];
        if (!empty($mergeModuleConfig['shot'])) {
            $moduleCodes = explode(',', $mergeModuleConfig['shot']);
        }
        $moduleIds = [];
        foreach ($moduleCodes as $tmpModuleCode) {
            $moduleIds[] = Module::$moduleDictData['module_index_by_code'][$tmpModuleCode]['id'];
        }
        $entityFilter = [
            'entity.tenant_id' => $currentTenantId,
            'entity.project_id' => $projectId,
            'entity.is_generate' => 'yes',
            'entity.module_id' => ['IN', implode(',', $moduleIds)],
        ];
        if ($episodeId > 0) {
            $episode = model(EntityModel::class)
                ->field("id,code")
                ->find($episodeId);
            if (empty($episode)) {
                throw new LogicException('episode not found', ErrorCode::MISSING_EPISODE);
            }
            $entityFilter['entity.initial_episode_code'] = $episode['code'];
        }

        $entityFilter = array_merge($entityFilter, $extraEntityFilter);

        $res['total'] = $this->entityModel
            ->join('task on task.entity_id = entity.id and task.step_type=\'step\'')
            ->join('module on module.id = task.entity_module_id')
            //            ->join('step_category on step_category.id = task.step_category_id', 'LEFT')
            ->where($entityFilter)->cache(30)->count();
        if ($res['total'] === 0) {
            return $res;
        }

        $entityQueryFields = ['entity.id', 'entity.name', 'entity.code', 'entity.duration', 'entity.showings_number', 'entity.initial_episode_code',
            'entity.module_id', 'entity.entity_id', 'entity.entity_module_id', 'entity.json', 'entity.is_assignee',
            'entity.plan_start_time', 'entity.plan_end_time',];

        $entityTaskQueryFields = [
            ...$entityQueryFields,
            'task.id', 'task.name', 'task.code', 'task.entity_id', 'task.step_category_id', 'task.step_id', 'task.step_type',
            'task.pre_task_id', 'task.executor_tenant_id', 'task.assignee_producer', 'task.assignee', 'task.executor', 'task.tenant_id',
            'task.executor_confirmed', 'task.assignee_at', 'task.is_assignee', 'task.assign_status', 'task.task_status',
            'task.plan_start_time', 'task.plan_end_time', 'task.start_time', 'task.end_time', 'task.department_id',
//            'status.id', 'status.code', 'status.name',
        ];
        $entityTaskList = $this->entityModel
            ->join('task on task.entity_id = entity.id and task.step_type=\'step\'')
            ->join('module on module.id = task.entity_module_id')
            //            ->join('step_category on step_category.id = task.step_category_id', 'LEFT')
//            ->join("status on status.id = json_unquote(json_extract(task.json,'$.task_status'))", 'LEFT')
            ->where($entityFilter)
            ->page($page[0], $page[1])
            ->field(build_complex_query_fields($entityTaskQueryFields, '__'))
            ->order($order)
            ->select();
        $insideSupplierUserId = [];
        $outsideSupplierTenantId = [];
        $stepCategoryData = model(StepCategoryModel::class)
            ->where([
                'entity_id' => ['IN', "$shotModuleId,$sequenceModuleId"],
                'parent_id' => 0,
            ])
            ->field('id,name,code,entity_id')
            ->select();
        $stepCategoryData = array_column($stepCategoryData, null, 'entity_id');
        $sequenceList = [];
        $querySequenceIdList = [];
        $taskListGroupedBySequenceId = [];
        $departmentIdMap = [];
        $episodeCodeList = [];
        foreach ($entityTaskList as $sequence) {
            $sequence = separate_complex_query_data($sequence, '__');
            $entity = $sequence['entity'];
            $task = $sequence['task'];
            if ($entity['module_id'] === $sequenceModuleId) {
                $task['sequence_id'] = $entity['id'];
                if (!array_key_exists($entity['id'], $sequenceList)) {
                    $sequenceList[$entity['id']] = $entity;
                }
            } else if ($entity['module_id'] === $shotModuleId) {

                if (!in_array($entity['entity_id'], $querySequenceIdList)) {
                    $querySequenceIdList[] = $entity['entity_id'];
                }
                $task['sequence_id'] = $entity['entity_id'];
            }
            if ($task['assignee'] > 0) {
                $insideSupplierUserId[] = $task['assignee'];
            }
            if ($task['executor_tenant_id'] > 0 && $task['executor_tenant_id'] != $currentTenantId && !in_array($task['executor_tenant_id'], $outsideSupplierTenantId)) {
                $outsideSupplierTenantId[] = $task['executor_tenant_id'];
            }
            if ($task['department_id'] > 0) {
                $departmentIdMap[$task['department_id']] = $task['department_id'];
            }

            if (!empty($task['sequence_id'])) {
                $taskListGroupedBySequenceId[$task['sequence_id']][] = $task;
            }
            if (!empty($entity['initial_episode_code'])) {
                $episodeCodeList[$entity['initial_episode_code']] = $entity['initial_episode_code'];
            }
        }
        if (!empty($querySequenceIdList)) {
            $querySequenceList = model(EntityModel::class)->where(['id' => ['IN', implode(',', $querySequenceIdList)]])->field($entityQueryFields)->select();
            if (!empty($querySequenceList)) {
                $sequenceList = array_column($querySequenceList, null, 'id') + $sequenceList;
            }
        }
        // 供应商信息
        $taskService = TaskService::getInstance();
        $supplierRes = $taskService->queryTaskSupplierInfo($currentTenantId, $insideSupplierUserId, $outsideSupplierTenantId, $departmentIdMap);

        // 集查询
        $episodeList = [];
        if (!empty($episodeCodeList)) {
            $episodeList = EpisodeService::getInstance()->selectEpisodeMap(['project_id' => $projectId, 'code' => ['IN', array_keys($episodeCodeList)]]);
        }
        $statusService = StatusService::getInstance();
        $notStartedStatusList = $statusService->getNotStartedStatus();
        $notStartedStatusIdList = array_column($notStartedStatusList, 'id');
        foreach ($taskListGroupedBySequenceId as $sequenceId => $taskList) {
            unset($sequence);
            $sequence = $sequenceList[$sequenceId] ?? null;
            if (empty($sequence)) {
                continue;
            }
            $sequence['episode'] = $episodeList[$sequence['initial_episode_code']] ?? null;
            $sequence['step_category'] = $stepCategoryData[$sequence['module_id']] ?? null;
            $sequence['task_ids'] = [];
            $sequence['executor'] = '';
            $sequence['wait_assign_count'] = 0;
            $sequence['plan_start_time'] = $sequence['plan_end_time'] = 0;
            $sequenceDepartmentId = [];
            $sequence['can_withdraw_task_ids'] = [];
            foreach ($taskList as $task) {
                // 对比出序列的开始时间和结束时间
                if ($task['plan_start_time'] > 0 && ($task['plan_start_time'] < $sequence['plan_start_time'] || $sequence['plan_start_time'] == 0)) {
                    $sequence['plan_start_time'] = $task['plan_start_time'];
                }
                if ($task['plan_end_time'] > 0 && ($task['plan_end_time'] > $sequence['plan_end_time'] || $sequence['plan_end_time'] == 0)) {
                    $sequence['plan_end_time'] = $task['plan_end_time'];
                }
                $task['is_outside'] = false;
                if ($task['executor_tenant_id'] > 0 && $task['executor_tenant_id'] != $currentTenantId) {
                    $task['assignee_user'] = $supplierRes['outside'][$task['executor_tenant_id']] ?? null;
                    $task['is_outside'] = true;
                } else if ($task['department_id'] > 0) {
                    $task['assignee_user'] = $supplierRes['department'][$task['department_id']] ?? null;
                    if (!empty($task['department_info']) && !in_array($task['department_id'], $sequenceDepartmentId)) {
                        $sequence['department_info'][] = $task['department_info']['name'];
                    }
                    if (in_array($task['task_status'], $notStartedStatusIdList)) {
                        $sequence['can_withdraw_task_ids'][] = $task['id'];
                    }
                }

                $task['supplier_info'] = null;
                if ($task['executor_tenant_id'] > 0 && $task['executor_tenant_id'] != $task['tenant_id']) {
                    $task['supplier_info'] = $supplierRes['outside'][$task['executor_tenant_id']] ?? null;
                } else if ($task['department_id'] > 0) {
                    $task['supplier_info'] = $supplierRes['department'][$task['department_id']] ?? null;
                    if (!empty($task['supplier_info']) && !in_array($task['department_id'], $sequenceDepartmentId)) {
                        $sequence['supplier_info'][] = $task['supplier_info']['name'];
                    }
                }

                if (!empty($task['assignee_user'])) {
                    $executorTaskName = $task['name'] . "({$task['assignee_user']['name']})";
                    if (strpos($sequence['executor'], $executorTaskName) === false) { //去除重复
                        $sequence['executor'] .= $executorTaskName . ",";
                    }
                }
                $sequence['task_ids'][] = $task['id'];
                if ($task['assign_status'] === 'default' || $task['assign_status'] === 'rejected') {
                    $sequence['wait_assign_count'] += 1;
                }
            }
//            unset($sequence['children']);
            if (count($sequence['can_withdraw_task_ids']) !== count($taskList)) {
                $sequence['can_withdraw_task_ids'] = [];
            }
            $sequence['executor'] = trim($sequence['executor'], ',');
            $res['rows'] [] = $sequence;
        }
        return $res;
    }

    /**
     * 分配任务弹出任务树查询
     * @param $taskIdList
     * @return array
     */
    public function getAssignPopTaskTree($taskIdList)
    {
        $entityFilter = ['entity.is_generate' => 'yes', 'task.step_type' => 'step', 'task.id' => ['IN', implode(',', $taskIdList)]];
        $entityQueryFields = [
            'entity.id', 'entity.name', 'entity.code', 'entity.duration', 'entity.showings_number', 'entity.initial_episode_code', 'entity.description',
            'entity.module_id', 'entity.entity_id', 'entity.entity_module_id', 'entity.json', 'entity.is_assignee', 'entity.project_id',
            'entity.plan_start_time', 'entity.plan_end_time', 'entity.director_star', 'entity.key_shot',
            'task.id', 'task.tenant_id', 'task.name', 'task.code', 'task.entity_id', 'task.entity_module_id', 'task.step_category_id', 'task.step_id', 'task.step_type',
            'task.pre_task_id', 'task.executor_tenant_id', 'task.assignee_producer', 'task.assignee', 'task.executor', 'task.is_lock',
            'task.executor_confirmed', 'task.assignee_at', 'task.is_assignee', 'task.assign_status', 'task.task_status',
            'task.plan_start_time', 'task.plan_end_time', 'task.department_id', 'task.json', 'task.tenant_group_id', 'task.executor_type', 'task.episode_id',
            'task.manual_man_hour', 'task.plan_delivery_time'
        ];
        $entityTaskList = $this->entityModel
            ->join('module on module.id = entity.module_id')
            ->join('task on task.entity_id = entity.id and task.step_type=\'step\'')
            ->join('step_category on step_category.id = task.step_category_id', 'LEFT')
            ->join("status on status.id = json_unquote(json_extract(task.json,'$.task_status'))", 'LEFT')
            ->where($entityFilter)
            ->field(build_complex_query_fields($entityQueryFields, '__'))
            ->select();

        $insideSupplierUserId = [];
        $outsideSupplierTenantId = [];
        $taskListGroupedByStepId = [];
        $departmentIdMap = [];
        $executorMap = [];
        $episodeCode = '';
        $projectId = 0;
        $tenantId = 0;
        $tenantGroupIds = [];
        $stepCategoryIdList = [];
        $stepIdList = [];
        $episodeIds = [];
        $episodeStepCategoryWhere = [];
        foreach ($entityTaskList as $entityTask) {
            $entityTask = separate_complex_query_data($entityTask, '__');
            $entity = $entityTask['entity'];
            $task = $entityTask['task'];
            $task['entity'] = $entity;

            $episodeIds[$task['episode_id']] = $task['episode_id'];
            $episodeStepCategoryWhere[] = [
                'plan.entity_id' => $task['episode_id'],
                's_tag.link_id' => $task['step_category_id']
            ];
            $stepCategoryIdList[$task['step_category_id']] = $task['step_category_id'];
            if (empty($episodeCode)) {
                $episodeCode = $entity['initial_episode_code'];
            }
            if (empty($projectId)) {
                $projectId = $entity['project_id'];
            }
            if (empty($tenantId)) {
                $tenantId = $task['tenant_id'];
            }

            $task['sequence_id'] = $task['entity_id'];
            if ($task['assignee'] > 0) {
                $insideSupplierUserId[] = $task['assignee'];
                $executorMap[$task['assignee']] = $task['assignee'];
            }
            if ($task['executor_tenant_id'] > 0 && $task['executor_tenant_id'] != $task['tenant_id'] && !in_array($task['executor_tenant_id'], $outsideSupplierTenantId)) {
                $outsideSupplierTenantId[] = $task['executor_tenant_id'];
            }
            $taskListGroupedByStepId[$task['step_id']][] = $task;
            if (!in_array($task['step_id'], $stepIdList)) {
                $stepIdList[] = $task['step_id'];
            }
            if ($task['department_id'] > 0) {
                $departmentIdMap[$task['department_id']] = $task['department_id'];
            }
            if ($task['executor'] > 0) {
                $executorMap[$task['executor']] = $task['executor'];
            }
            if (!empty($task['tenant_group_id'])) {
                $tenantGroupIds[$task['tenant_group_id']] = $task['tenant_group_id'];
            }
        }
        $stepMap = [];
        if (!empty($stepIdList)) {
            $stepMap = model(StepModel::class)->where(['id' => ['IN', $stepIdList]])->field('id,name,color,code,step_category_id,is_dismantle_step')->select();
            $stepMap = array_column($stepMap, null, 'id');
        }
        // 剧集环节交付时间查询
        $episodeStepCategoryPlanMap = [];
        if (!empty($episodeIds) && !empty($stepCategoryIdList)) {
            $episodeStepCategoryPlanMap = PlanService::getInstance()->getEpisodeStepCategoryPlanObject($episodeIds, $stepCategoryIdList);
        }
        $tenantGroupIds = array_values($tenantGroupIds);
        // 用户信息
        $supplierRes = TaskService::getInstance()->queryTaskSupplierInfo($tenantId, $insideSupplierUserId, $outsideSupplierTenantId, $departmentIdMap, $executorMap, [], $tenantGroupIds);

        if (!empty($supplierRes["tenant_group"])) {
            $supplierRes["tenant_group"] = array_column($supplierRes["tenant_group"], null, 'id');
        }

        // 查询是否延期审核
        $taskIds = array_column($entityTaskList, 'task__id');
        $taskDelayMap = ReviewTaskDelayService::getInstance()->taskDelayInfo($taskIds);

        $res = [];
        foreach ($taskListGroupedByStepId as $stepId => $taskList) {
            $step = $stepMap[$stepId];
            // 工序=>序列=>任务
            // 任务通过序列信息合并
            $stepEntityList = [];
            foreach ($taskList as $task) {
                $entity = $task['entity'];
                if (empty($entity)) {
                    continue;
                }
                $jsonFields = json_decode($entity['json'], true);
                foreach ($jsonFields as $fieldKey => $fieldValue) {
                    $shotKey = str_replace_once(Module::$moduleDictData['module_index_by_id'][$entity['module_id']]['code'] . '_', '', $fieldKey);
                    //  避免覆盖实体的值
                    if (isset($entity[$shotKey])) {
                        continue;
                    }
                    $entity[$shotKey] = $fieldValue;
                }
                unset($entity['json']);
                $entity['task_ids'] = [$task['id']];
                $entity['task_id'] = $task['id'];
                $entity['plan_start_time'] = $task['plan_start_time'];
                $entity['plan_end_time'] = $task['plan_end_time'];
                $entity['plan_delivery_time'] = $task['plan_delivery_time'];
                $entity['step_category_id'] = $task['step_category_id'];
                $entity['wait_assign_count'] = 0;
                $entity['assign_status'] = $task['assign_status'];
                $entity['executor_type'] = $task['executor_type'];
                $entity['manual_man_hour'] = $task['manual_man_hour'];
                $entity['is_lock'] = $task['is_lock'] ?? "no";
                $entity['is_dismantle_step'] = $step['is_dismantle_step'];
                $entity['is_task_delay'] = !empty($taskDelayMap[$task['id']]);

                // 执行部门信息
                $entity['department_info'] = null;
                $entity['assignee_user'] = null;
                if ($task['executor_tenant_id'] > 0 && $task['executor_tenant_id'] != $task['tenant_id']) {
                    $entity['executor_tenant'] = $entity['assignee_user'] = $supplierRes['outside'][$task['executor_tenant_id']] ?? null;
                    if (!empty($task['tenant_group_id']) && isset($supplierRes["tenant_group"][$task['tenant_group_id']])) {
                        $entity['tenant_group'] = $entity['assignee_user']["tenant_group"] = $supplierRes["tenant_group"][$task['tenant_group_id']];
                    }
                } else if ($task['department_id'] > 0) {
                    $task['department_info'] = $supplierRes['department'][$task['department_id']] ?? null;
                    $entity['department_info'] = $task['department_info'];
                }
                // 内部制作 负责人
                if (($task['executor_tenant_id'] == 0 || $task['executor_tenant_id'] == $task['tenant_id']) && $task['assignee'] > 0) {
                    $entity['assignee_user'] = $supplierRes['executor'][$task['assignee']] ?? null;
                }
                // 执行人信息
                $entity['executor_info'] = null;
                if ($task['executor'] > 0) {
                    $entity['executor_info'] = $supplierRes['executor'][$task['executor']] ?? null;
                }
                $task['department_info'] = null;
                if ($task['assign_status'] === 'default' || $task['assign_status'] === 'rejected') {
                    $entity['wait_assign_count'] += 1;
                }
                $taskJson = json_decode($task['json'], true);
                $entity['dismantle_name'] = $taskJson['dismantle_name'] ?? null;
                $entity['is_dismantle_task'] = $taskJson['is_dismantle_task'] ?? null;
                $entity['team'] = $taskJson['team'] ?? [];
                $entity['plan_data'] = null;

                //判断属性排期
                if (!empty($entity['category']) && !empty($episodeStepCategoryPlanMap[$task['episode_id']][$task['step_category_id'].'#'.$entity['category']])) {
                    $entity['plan_data'] = $episodeStepCategoryPlanMap[$task['episode_id']][$task['step_category_id'].'#'.$entity['category']];
                } else {
                    if (!empty($episodeStepCategoryPlanMap[$task['episode_id']][$task['step_category_id']])) {
                        $entity['plan_data'] = $episodeStepCategoryPlanMap[$task['episode_id']][$task['step_category_id']];
                    }
                }
                $stepEntityList[] = $entity;
            }
            $step['children'] = $stepEntityList;
            $res[] = $step;
        }

        return ['plan' => null, 'rows' => array_values($res)];
    }

    /**
     * 序列废除
     * @param $status
     * @param $param
     * @return bool
     * @throws Exception
     */
    public function seqAbolitionOrEnabling($status, $param)
    {
        // 废除
        if ($status == 'Abo') {
            $AboModel = new SeqAbolitionService();
            // 处理废除任务
            return $AboModel->execAbo($param);
        }
        return false;
    }

    public function getStoryboard($id)
    {
        $entity = model(EntityModel::class)->where(['id' => $id])->find();
        if (empty($entity)) {
            throw new LogicException("entity not found", ErrorCode::ENTITY_NOT_FOUND);
        }
        $entity['json'] = json_decode(empty($entity['json']) ? '{}' : $entity['json'], true);
        if (module_by_id($entity['module_id'])['code'] == 'shot') {
            if (empty($entity['json']['shot_storyboard'])) {
                throw new LogicException('shot [shot_storyboard] storyboard not found', ErrorCode::ENTITY_NOT_FOUND);
            }
            $entity = model(EntityModel::class)->where(['id' => $entity['json']['shot_storyboard']])->find();
            if (empty($entity)) {
                throw new LogicException("entity not found", ErrorCode::ENTITY_NOT_FOUND);
            }
            $entity['json'] = json_decode(empty($entity['json']) ? '{}' : $entity['json'], true);
        }
        return $entity;
    }

    /**
     * 关联分镜列表
     * @param $id
     * @param $param
     * @return array
     */
    public function relateStoryboardList($id, $param)
    {
        $entity = $this->getStoryboard($id);
        $filter = $param['filter'] ?? [];
        $filter[] = [
            'storyboard.id' => ['NEQ', $entity['id']],
        ];
        if (!empty($entity['json']['storyboard_relate_storyboard'])) {
            $filter[] = [
                [
                    'storyboard.project_id' => $entity['project_id'],
                    'storyboard.initial_episode_code' => $entity['initial_episode_code'],
                    'storyboard.showings_number' => $entity['showings_number'],
                ],
                ['storyboard.id' => ['IN', $entity['json']['storyboard_relate_storyboard']]],
                '_logic' => 'OR',
            ];
        } else {
            $filter[] = [
                'storyboard.project_id' => $entity['project_id'],
                'storyboard.initial_episode_code' => $entity['initial_episode_code'],
                'storyboard.showings_number' => $entity['showings_number'],
            ];
        }
        $param['filter'] = $filter;
        return EntityService::getInstance()->getList($param, 'storyboard');
    }

    /**
     * 关联分镜列表
     * @param $id
     * @param $param
     * @return array
     */
    public function unRelateStoryboardList($id, $param)
    {
        $entity = $this->getStoryboard($id);
        $filter = $param['filter'] ?? [];
        $filter[] = [
            'storyboard.id' => ['NEQ', $entity['id']],
        ];
        if (!empty($entity['json']['storyboard_relate_storyboard'])) {
            $filter[] = [
                [
                    'storyboard.project_id' => $entity['project_id'],
                    'storyboard.initial_episode_code' => ['NEQ', $entity['initial_episode_code']],
                    'storyboard.showings_number' => ['NEQ', $entity['showings_number']],
                ],
                ['storyboard.id' => ['NOT IN', $entity['json']['storyboard_relate_storyboard']]],
            ];
        } else {
            $filter[] = [
                'storyboard.project_id' => $entity['project_id'],
                'storyboard.initial_episode_code' => ['NEQ', $entity['initial_episode_code']],
                'storyboard.showings_number' => ['NEQ', $entity['showings_number']],
            ];
        }
        $param['filter'] = $filter;
        return EntityService::getInstance()->getList($param, 'storyboard');
    }

    /**
     * 设置关联镜头
     * @param int $id
     * @param array $relateIdList
     * @param string $action
     * @return array|bool
     * @throws Exception
     */
    public function setRelateStoryboard(int $id, array $relateIdList, string $action)
    {
        $entity = $this->getStoryboard($id);
        $entityRelateStoryboardList = $entity['json']['storyboard_relate_storyboard'] ?? '';
        $entityRelateStoryboardList = explode(',', $entityRelateStoryboardList);
        if ($action == 'delete') {
            $entityRelateStoryboardList = array_filter($entityRelateStoryboardList, function ($i) use ($relateIdList) {
                return !in_array($i, $relateIdList);
            });
        } else {
            $entityRelateStoryboardList = array_merge($entityRelateStoryboardList, $relateIdList);
            $entityRelateStoryboardList = array_unique($entityRelateStoryboardList);
        }
        $updateData = [
            'id' => $entity['id'],
            'storyboard_relate_storyboard' => implode(',', $entityRelateStoryboardList),
        ];
        return CommonService::instance('entity')->update($updateData, 'storyboard', false);
    }

    /**
     * 查询分镜和镜头
     * @param $idList
     * @return array
     */
    public function getStoryboardsShots($idList)
    {
        $entityList = model(EntityModel::class)->where(['id' => ['IN', implode(',', $idList)]])->select();
        if (empty($entityList)) {
            throw new LogicException("entity not found", ErrorCode::ENTITY_NOT_FOUND);
        }
        $res = [];
        $shotModule = module_by_code('shot');
        foreach ($entityList as $entity) {
            $entity['json'] = json_decode(empty($entity['json']) ? '{}' : $entity['json'], true);
            $res[] = $entity;
            if ($shotModule['id'] == $entity['module_id']) {
                if (empty($entity['json']['shot_storyboard'])) {
                    throw new LogicException('shot [shot_storyboard] storyboard not found', ErrorCode::ENTITY_NOT_FOUND);
                }
                $entity = model(EntityModel::class)->where(['id' => $entity['json']['shot_storyboard']])->find();
                if (empty($entity)) {
                    throw new LogicException("entity not found", ErrorCode::ENTITY_NOT_FOUND);
                }
                $entity['json'] = json_decode(empty($entity['json']) ? '{}' : $entity['json'], true);
                $res[] = $entity;
            } else {
                $entity = model(EntityModel::class)->where(['module_id' => $shotModule['id'], 'project_id' => $entity['project_id'], 'initial_episode_code' => $entity['initial_episode_code'], 'showings_number' => $entity['showings_number'], 'name' => $entity['name']])->find();
                if (!empty($entity)) {
                    $entity['json'] = json_decode(empty($entity['json']) ? '{}' : $entity['json'], true);
                    $res[] = $entity;
                }
            }
        }
        return $res;
    }

    /**
     * 设置关键镜头
     * @param $shotIdList
     * @param $isKeyShot
     * @return int
     */
    public function setKeyShot($shotIdList, $isKeyShot)
    {
        $storyboardList = $this->getStoryboardsShots($shotIdList);
        $storyboardIds = implode(',', array_column($storyboardList, 'id'));
        return model(EntityModel::class)->execute("update entity set key_shot = '{$isKeyShot}' where id in ({$storyboardIds})");
    }


    /**
     * 分配任务弹出任务树查询
     * @param $taskIdList
     * @return array
     */
    public function getPopUpdateTimeTaskTree($taskIdList)
    {
        // 任务区分 (待办,工序任务)
        $taskDataList = model(TaskModel::class)->where(['id' => ['IN', implode(',', $taskIdList)]])->field([
            'task.id', 'task.tenant_id', 'task.name', 'task.code', 'task.entity_id', 'task.entity_module_id', 'task.step_category_id', 'task.step_id', 'task.step_type',
            'task.pre_task_id', 'task.executor_tenant_id', 'task.assignee_producer', 'task.assignee', 'task.executor',
            'task.executor_confirmed', 'task.assignee_at', 'task.is_assignee', 'task.assign_status',
            'task.plan_start_time', 'task.plan_end_time', 'task.department_id', 'task.json', 'task.executor_type', 'task.episode_id',
            'task.manual_man_hour', 'task.plan_delivery_time',
        ])->select();

        $todoTaskDataList = [];
        $entityIds = [];
        $stepIdList = [];
        $taskListGroupedByStepId = [];
        $stepCategoryIdList = [];
        $episodeStepCategoryMap = [];
        $taskTagMap = [];
        $taskIdList = [];
        foreach ($taskDataList as $taskDataItem) {
            if (in_array($taskDataItem['step_type'], TaskModel::STEP_TYPE_TODO_GROUP)) {
                $todoTaskDataList[] = $taskDataItem;
            } elseif ($taskDataItem['step_type'] == TaskModel::STEP_TYPE_STEP) {
                $entityIds[$taskDataItem['entity_id']] = $taskDataItem['entity_id'];
                $taskListGroupedByStepId[$taskDataItem['step_id']][] = $taskDataItem;
                if (!in_array($taskDataItem['step_id'], $stepIdList)) {
                    $stepIdList[] = $taskDataItem['step_id'];
                }
                $stepCategoryIdList[$taskDataItem['step_category_id']] = $taskDataItem['step_category_id'];
                $episodeStepCategoryMap[$taskDataItem['episode_id']][] = $taskDataItem['step_category_id'];

                $taskTagMap[$taskDataItem['id']][$taskDataItem['episode_id'] . '#' . $taskDataItem['step_category_id']] = $taskDataItem['episode_id'] . '#' . $taskDataItem['step_category_id'];
            }
            $taskIdList[] = $taskDataItem['id'];
        }

        // 获取计划交付时间
        $episodeStepCategoryPlanMap = TodoService::getInstance()->getPlanDeliveryTime(array_column($todoTaskDataList, 'id'), $episodeStepCategoryMap, $taskTagMap);

        $entityList = [];
        if (!empty($entityIds)) {
            $entityList = model(EntityModel::class)
                ->where(["id" => ["IN", $entityIds]])
                ->field([
                    'entity.id', 'entity.name', 'entity.code', 'entity.duration', 'entity.showings_number', 'entity.initial_episode_code', 'entity.description',
                    'entity.module_id', 'entity.entity_id', 'entity.entity_module_id', 'entity.json', 'entity.is_assignee', 'entity.project_id',
                    'entity.plan_start_time', 'entity.plan_end_time', 'entity.director_star', 'entity.key_shot',
                ])
                ->select();
        }

        $entityMap = array_column($entityList, null, 'id');

        $stepMap = [];
        if (!empty($stepIdList)) {
            $stepMap = model(StepModel::class)->where(['id' => ['IN', $stepIdList]])->field('id,name,color,code,step_category_id,is_dismantle_step')->select();
            $stepMap = array_column($stepMap, null, 'id');
        }

        // 查询是否延期审核
        $taskDelayMap = ReviewTaskDelayService::getInstance()->taskDelayInfo($taskIdList);

        $res = [];
        foreach ($taskListGroupedByStepId as $stepId => $taskList) {
            $step = $stepMap[$stepId];
            // 工序=>序列=>任务
            // 任务通过序列信息合并
            $stepEntityList = [];
            foreach ($taskList as $task) {
                $entity = $entityMap[$task['entity_id']] ?? null;
                if (empty($entity)) {
                    continue;
                }
                $jsonFields = json_decode($entity['json'], true);
                foreach ($jsonFields as $fieldKey => $fieldValue) {
                    $shotKey = str_replace_once(Module::$moduleDictData['module_index_by_id'][$entity['module_id']]['code'] . '_', '', $fieldKey);
                    //  避免覆盖实体的值
                    if (isset($entity[$shotKey])) {
                        continue;
                    }
                    $entity[$shotKey] = $fieldValue;
                }

                $entity['task_ids'] = [$task['id']];
                $entity['task_id'] = $task['id'];
                $entity['plan_start_time'] = $task['plan_start_time'];
                $entity['plan_end_time'] = $task['plan_end_time'];
                $entity['step_category_id'] = $task['step_category_id'];
                $entity['manual_man_hour'] = $task['manual_man_hour'];
                $entity['is_dismantle_step'] = $step['is_dismantle_step'];
                $entity['is_task_delay'] = !empty($taskDelayMap[$task['id']]);

                $taskJson = json_decode($task['json'], true);
                $entity['dismantle_name'] = $taskJson['dismantle_name'] ?? null;
                $entity['is_dismantle_task'] = $taskJson['is_dismantle_task'] ?? null;
                $entity['plan_delivery_time'] = $task['plan_delivery_time'];
                $entity['step_type'] = $task['step_type'];
                //交付时间
                $entity['delivery_plan'] = $episodeStepCategoryPlanMap[$task['id']] ?? null;
                $stepEntityList[] = $entity;
            }
            $step['children'] = $stepEntityList;
            $res[] = $step;
        }

        //在顶部插入待办
        if (!empty($todoTaskDataList)) {
            $todoTaskDataList = array_map(function ($todoTaskDataItem) use ($taskTagMap, $episodeStepCategoryPlanMap) {
                $todoTaskDataItem['task_id'] = $todoTaskDataItem['id'];
                $todoTaskDataItem['delivery_plan'] = $episodeStepCategoryPlanMap[$todoTaskDataItem['id']] ?? null;

                return $todoTaskDataItem;
            }, $todoTaskDataList);

            array_unshift($res, [
                'id' => '待办',
                'name' => '待办',
                'code' => 'todo',
                'children' => $todoTaskDataList
            ]);
        }


        return ['rows' => $res];
    }

}

